typedef struct {
GList *sequences;
+ GList *files;
const char *compose_file;
} GtkComposeParser;
parser = g_new (GtkComposeParser, 1);
parser->sequences = NULL;
+ parser->files = NULL;
parser->compose_file = NULL;
return parser;
parser_free (GtkComposeParser *parser)
{
g_list_free_full (parser->sequences, (GDestroyNotify) gtk_compose_data_free);
+ g_list_free_full (parser->files, g_free);
g_free (parser);
}
return FALSE;
}
+static void parser_parse_file (GtkComposeParser *parser,
+ const char *path);
+
+static void
+parser_handle_include (GtkComposeParser *parser,
+ const char *line)
+{
+ const char *p;
+ const char *start, *end;
+ char *path;
+
+ p = line + strlen ("include ");
+
+ while (g_ascii_isspace (*p))
+ p++;
+
+ if (*p != '"')
+ goto error;
+
+ p++;
+
+ start = p;
+
+ while (*p && *p != '"')
+ p++;
+
+ if (*p != '"')
+ goto error;
+
+ end = p;
+
+ p++;
+
+ while (g_ascii_isspace (*p))
+ p++;
+
+ if (*p && *p != '#')
+ goto error;
+
+ path = g_strndup (start, end - start);
+
+ parser_parse_file (parser, path);
+
+ g_free (path);
+
+ return;
+
+error:
+ g_warning ("Could not parse include: %s", line);
+}
+
static void
parser_parse_line (GtkComposeParser *parser,
const char *line)
return;
if (g_str_has_prefix (line, "include "))
- return;
+ {
+ parser_handle_include (parser, line);
+ return;
+ }
components = g_strsplit (line, ":", 2);
return retval;
}
+static char *
+canonicalize_filename (const char *path)
+{
+ GFile *file;
+ char *retval;
+
+ file = g_file_new_for_path (path);
+ retval = g_file_get_path (file);
+
+ g_object_unref (file);
+
+ return retval;
+}
+
static void
parser_parse_file (GtkComposeParser *parser,
const char *compose_file)
{
+ char *path;
+
// stash the name for the table hash
if (parser->compose_file == NULL)
parser->compose_file = compose_file;
- parser_read_file (parser, compose_file);
+ path = canonicalize_filename (compose_file);
+
+ if (g_list_find_custom (parser->files, path, (GCompareFunc)strcmp))
+ {
+ g_warning ("include cycle detected: %s", compose_file);
+ g_free (path);
+ return;
+ }
+
+ parser->files = g_list_prepend (parser->files, path);
+
+ parser_read_file (parser, path);
+
+ parser->files = g_list_remove (parser->files, path);
}
static GtkComposeTable *
--- /dev/null
+include "testsuite/gtk/compose/cycle" # create an include cycle
+
+<Multi_key> <s> <e> <q> : "!"
--- /dev/null
+include "testsuite/gtk/compose/included" # see if this works
+
+<Multi_key> <s> <e> <q> : "!"
--- /dev/null
+# n_seqs: 2
+# max_seq_len: 4
+<Uff20> <U73> <U61> <U73> : "\"\\"
+<Uff20> <U73> <U65> <U71> : "!" # U21
--- /dev/null
+<Multi_key> <s> <a> <s> : "\"\\"
--- /dev/null
+include "testsuite/gtk/compose/nosuchfile" # this file does not exist
+
+<Multi_key> <s> <e> <q> : "!"
g_free (expected);
}
+static void
+compose_table_cycle (void)
+{
+ if (g_test_subprocess ())
+ {
+ char *file;
+ GtkComposeTable *table;
+
+ file = g_build_filename (g_test_get_dir (G_TEST_DIST), "compose", "cycle", NULL);
+
+ table = gtk_compose_table_new_with_file (file);
+ g_assert_nonnull (table);
+ g_free (file);
+
+ return;
+ }
+
+ g_test_trap_subprocess (NULL, 0, 0);
+ g_test_trap_assert_stderr ("*include cycle detected*");
+ g_test_trap_assert_failed ();
+}
+
+static void
+compose_table_nofile (void)
+{
+ if (g_test_subprocess ())
+ {
+ char *file;
+ GtkComposeTable *table;
+
+ file = g_build_filename (g_test_get_dir (G_TEST_DIST), "compose", "nofile", NULL);
+
+ table = gtk_compose_table_new_with_file (file);
+ g_assert_nonnull (table);
+ g_free (file);
+
+ return;
+ }
+
+ g_test_trap_subprocess (NULL, 0, 0);
+ g_test_trap_assert_stderr ("*No such file or directory*");
+ g_test_trap_assert_failed ();
+}
+
/* Check matching against a small table */
static void
compose_table_match (void)
g_test_add_data_func ("/compose-table/codepoint", "codepoint", compose_table_compare);
g_test_add_data_func ("/compose-table/multi", "multi", compose_table_compare);
g_test_add_data_func ("/compose-table/strings", "strings", compose_table_compare);
+ g_test_add_data_func ("/compose-table/include", "include", compose_table_compare);
+ g_test_add_func ("/compose-table/include-cycle", compose_table_cycle);
+ g_test_add_func ("/compose-table/include-nofile", compose_table_nofile);
g_test_add_func ("/compose-table/match", compose_table_match);
g_test_add_func ("/compose-table/match-compact", compose_table_match_compact);
g_test_add_func ("/compose-table/match-algorithmic", match_algorithmic);